/*
 * Copyright (C) 2012 DataSymphony (http://datasymphony.com.au)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package au.com.ds.restty.http;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.AbstractHttpMessage;

import au.com.ds.restty.Out;
import au.com.ds.restty.Out.Level;
import au.com.ds.restty.exc.HttpConnectorError;
import au.com.ds.restty.util.Utils;

public class HttpConnector {
	private HttpClient mClient;
	
	public HttpConnector(){
		mClient = new DefaultHttpClient();
	}
	
	public String callService(HttpCommand cmd){
		StringBuilder sb = new StringBuilder();
		
		switch (cmd.getMethod()) {
		case GET:
			processGetRequest(cmd, sb);
			break;
		case POST:
			processPostRequest(cmd, sb);
			break;
		case PUT:
			processPutRequest(cmd, sb);
			break;
		case DELETE:
			processDeleteRequest(cmd, sb);
			break;
		}
		
		return sb.toString();
	}
	
	public void processGetRequest(HttpCommand cmd, StringBuilder sb){
		Out.normal("Request:");
		Out.normal("\tGET " + cmd.getUrl() + "\n");
		HttpGet get = new HttpGet(cmd.getUrl());
		setHeaders(cmd, get);
		execute(get, sb);
	}
	
	public void processPostRequest(HttpCommand cmd, StringBuilder sb){
		Out.normal("Request:");
		Out.normal("\tPOST " + cmd.getUrl() + "\n");
		HttpPost post = new HttpPost(cmd.getUrl());
		setHeaders(cmd, post);
		try {
			Out.normal("Request body is: " + cmd.getBody() + "\n");
			
			StringEntity putBody = new StringEntity(cmd.getBody());
			post.setEntity(putBody);
			execute(post, sb);
		} catch (IOException e) {
			throw new HttpConnectorError("HTTP connection error", e);
		}
	}
	
	public void processPutRequest(HttpCommand cmd, StringBuilder sb){
		Out.normal("Request:");
		Out.normal("\tPUT " + cmd.getUrl() + "\n");
		HttpPut put = new HttpPut(cmd.getUrl());
		setHeaders(cmd, put);
		try {
			Out.normal("Request body is: " + cmd.getBody() + "\n");

			StringEntity putBody = new StringEntity(cmd.getBody());
			put.setEntity(putBody);
			execute(put, sb);
		} catch (IOException e) {
			throw new HttpConnectorError("HTTP connection error", e);
		}
	}
	
	public void processDeleteRequest(HttpCommand cmd, StringBuilder sb){
		Out.normal("Request:");
		Out.normal("\tDELETE " + cmd.getUrl() + "\n");
		HttpDelete delete = new HttpDelete(cmd.getUrl());
		setHeaders(cmd, delete);
		execute(delete, sb);
	}
	
	private static void setHeaders(HttpCommand cmd, AbstractHttpMessage request){
		Map<String, String> header = cmd.getHeader();
		if (header != null && !header.isEmpty()) {
			Out.debug("Headers:");
			for (Map.Entry<String, String> e : header.entrySet()) {
				request.setHeader(e.getKey(), e.getValue());
				Out.debug("\t" + e.getKey() + ": \"" + e.getValue() + "\"");
			}
			Out.debug("");
		}
	}
	
	private void execute(HttpUriRequest request, StringBuilder sb){
		InputStream is = null;
		try {
			HttpResponse response = mClient.execute(request);
			if (Out.getLevel() == Level.debug) {
				Out.debug("Response Headers:");
				Header[] headers = response.getAllHeaders();
				for (Header header : headers) {
					Out.debug("\t" + header.getName() + ": \"" + header.getValue() + "\"");
				}
				Out.debug("");
			}
			
			HttpEntity e = response.getEntity();
			if (e != null) {
				is = e.getContent();
				Utils.copyStream(is, sb);
			}
		} catch (Exception e) {
			throw new HttpConnectorError("HTTP connection error", e);
		} finally {
			if (is != null){
				try { is.close(); } catch (IOException e) {}
			}
		}
	}
}
